package com.example.demo.api;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import com.example.demo.common.AjaxResult;
import com.example.demo.common.AppVariable;
import com.example.demo.common.PasswordUtils;
import com.example.demo.common.UserSessionUtils;
import com.example.demo.game.*;
import com.example.demo.model.User;
import com.example.demo.model.UserMapper;
import com.example.demo.model.Vo.UserinfoSecret;
import com.example.demo.model.Vo.UserinfoVO;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.jdbc.Null;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

@RestController
@RequestMapping("/user")
public class UserAPI {

    @Resource
    private UserMapper userMapper;

    /**
     * 用户登录
     */
    @RequestMapping("/login")
    public AjaxResult login(String username, String password, String code, HttpServletRequest request){
        // 1.非空校验
        if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
            return AjaxResult.fail(-1, "用户名或密码为空!");
        }

        User userinfo = userMapper.selectByName(username);
        if (userinfo == null) {
            return AjaxResult.fail(-2, "账号未注册!");
        }
        //拿到验证码
//        String imgCode = UserSessionUtils.getImgCode(request);
        String imgCode = "code";
        System.out.println("code+" + code);
        System.out.println("imgcode+" +imgCode);
        if (!code.equals(imgCode)){
            return AjaxResult.fail(-3,"验证码输入错误");
        }
        // 2.判断密码是否相等
        if (PasswordUtils.check(password,userinfo.getPassword()) && userinfo.getState() != 6){
            // 登陆成功
            // 将用户存储到 session 中
            // 需要创建会话，所以设为 true
            HttpSession session = request.getSession();
            session.setAttribute("user",userinfo);

            userinfo.setPassword("");//返回前端前，隐藏敏感信息
            userMapper.updateUserStatefoById(1,userinfo.getUserId());
            return AjaxResult.success(userinfo);
        }else {
            /**
             * 密码错误就将 state 加一,给定最大允许密码错误次数，
             * 当 state - 1 大于最大次数时就等待 60s
             * state default 为1
             */
            int maxAttempts = 4;// 最大允许错误次数
            int waitTime = AppVariable.WAIT_TIME;//等待 60s
            if (userinfo.getState() > 5){
                // 此时用户以及超出最大允许错误次数,需要等待60s
                LocalDateTime localDateTime = LocalDateTime.now();
                LocalDateTime postTime = localDateTime.plusSeconds(waitTime);
                Duration duration = Duration.between(localDateTime, postTime);
                long delay = duration.toMillis();

                Timer timer = new Timer();
                if (userinfo.getState() != 1){
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            userMapper.updateUserStatefoById(1, userinfo.getUserId());
                        }
                    }, delay);
                    return AjaxResult.fail(-4, "密码错误次数过多，请等待 " + waitTime + " 秒后再试！");
                }
            }else {
                // 密码输入错误
                userMapper.updateUserStatefoById(userinfo.getState() + 1,userinfo.getUserId());
                return AjaxResult.fail(-5, "密码错误，剩余尝试次数：" + (maxAttempts - userinfo.getState() + 1));
            }
        }

        return AjaxResult.success(1);
    }

    /**
     * 注册
     * @param userinfo
     * @return
     */
    @RequestMapping("/reg")
    public AjaxResult addUser(User userinfo){
        // 非空校验
        if (userinfo == null ||
                !StringUtils.hasLength(userinfo.getUsername()) ||
                !StringUtils.hasLength(userinfo.getPassword())){
            return AjaxResult.fail(-1,"非法参数");
        }
        // 密码加盐加密
        userinfo.setPassword(PasswordUtils.encrypt(userinfo.getPassword()));
        return AjaxResult.success(userMapper.insert(userinfo));
    }

    /**
     *  登录之前添加验证码.
     */
    @GetMapping("/getcode")
    public void getCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 通知浏览器不要缓存
        response.setHeader("pragma", "no-cache");
        response.setHeader("cache-control", "no-cache");
        response.setHeader("expires", "0");


        // 生成一个验证码图片                                                // 宽          高   几位数的验证码     干扰点
        CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(116, 36, 4, 10);

        // 拿到图片生成的验证码
//        String code = circleCaptcha.getCode();
        String code = "code";
        System.out.println("code: " + code);

        // 每调用一次此方法, 就会生成新的 code, 存到 session[redis] 中
        HttpSession session = request.getSession(true);
        session.setAttribute(AppVariable.LOGIN_CHECK_CODE, code);

        // 拿到流对象
        ServletOutputStream outputStream = response.getOutputStream();
        if (outputStream != null) {
            // 通过输出流输出给前端
            circleCaptcha.write(outputStream);
            // 关闭资源
            outputStream.close();
        }
    }

    /**
     * 得到用户信息
     */
    @RequestMapping("/getUsernfo")
    public AjaxResult getUsernfo(HttpServletRequest request){
        User userinfo = UserSessionUtils.getSessionUser(request);
        userinfo = userMapper.showUserinfo(userinfo.getUserId());
        if (userinfo == null || !StringUtils.hasLength(userinfo.getUsername()) || userinfo.getUserId() <= 0){
            return AjaxResult.fail(-2,"用户为空，请重新登录!");
        }
        // 去除敏感数据(密码)
        userinfo.setPassword("");
        return AjaxResult.success(userinfo);

    }
    /**
     * 密保前的判断
     * @param request
     * @param username
     * @param password
     * @param code
     * @return
     */
    @RequestMapping("/judgesecret")
    public AjaxResult judgesecret(HttpServletRequest request, String username, String password,String code) {
        // 1. 非空校验
        if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
            return AjaxResult.fail(-1, "用户名或密码为空!");
        }

        User userinfo = userMapper.selectByName(username);
        if (userinfo == null) {
            return AjaxResult.fail(-2, "账号未注册!");
        }
        userMapper.updateUserStatefoById(1,userinfo.getState());
        // 2. 判断密码是否相等
        if (PasswordUtils.check(password, userinfo.getPassword()) && userinfo.getState() != 6) {
            // 登陆成功
            // 将用户存储到 session 中
            // 需要创建会话，所以设为 true
            HttpSession session = request.getSession();
            session.setAttribute("user", userinfo);
            userinfo.setPassword(""); // 返回前端之前，隐藏敏感(密码)信息
            userMapper.updateUserStatefoById(1,userinfo.getUserId());
            return AjaxResult.success(userinfo);
        } else {
            /**
             * 密码错误就将 state 加一,给定最大允许密码错误次数，当 state - 1 大于最大次数时就等待 60s
             * state default 为1
             */
            int maxAttempts = 3; // 最大允许密码错误次数
            int waitTime = 60; // 等待时间（秒）
            if (userinfo.getState() > 5) {
                LocalDateTime localTime = LocalDateTime.now();
                LocalDateTime postTime = localTime.plusSeconds(60);

                Duration duration = Duration.between(localTime, postTime);
                long delay = duration.toMillis();

                Timer timer = new Timer();
                if (userinfo.getState() != 1){
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            userMapper.updateUserStatefoById(1, userinfo.getUserId());
                        }
                    }, delay);
                    return AjaxResult.fail(-3, "密码错误次数过多，请等待 " + waitTime + " 秒后再试！");
                }
            } else {
                userMapper.updateUserStatefoById(userinfo.getState() + 1,userinfo.getUserId());
                return AjaxResult.fail(-4, "密码错误，剩余尝试次数：" + (maxAttempts - userinfo.getState() + 1));
            }
        }
        return AjaxResult.success(1);
    }

    /**
     * 判断密保答案是否正确
     * @return
     */
    @RequestMapping("/juganswer")
    public AjaxResult juganswer(UserinfoSecret userinfoSecret, Integer uid) {
        // 1. 非空校验
        if (userinfoSecret == null || !StringUtils.hasLength(userinfoSecret.getAnswer())) {
            return AjaxResult.fail(-1, "非法参数!");
        }

        // 2. 判断答案是否相等
        if (PasswordUtils.check(userinfoSecret.getAnswer(), userMapper.checkAnswer(uid))) {
            // 答案正确
            // 将用户存储到 session 中
            // 需要创建会话，所以设为 true
            userinfoSecret.setPassword(""); // 返回前端之前，隐藏敏感(密码)信息
            return AjaxResult.success(userinfoSecret);
        } else {
            return AjaxResult.fail(-1,"答案错误，请再次尝试");
        }
    }

    /**
     * 得到用户密保问题
     * @return
     */
    @RequestMapping("/initques")
    public AjaxResult initques(Integer uid){
        if (uid <= 0) {
            return AjaxResult.fail(-1, "非法参数!");
        }
        String question = userMapper.getQuestion(uid);
        if (question == null) {
            return AjaxResult.fail(-1, "非法用户!");
        }
        return AjaxResult.success(question);

    }

    /**
     * 展示个人信息
     * @param request
     * @return
     */
    @RequestMapping("/showuserinfo")
    public AjaxResult showuserinfo(HttpServletRequest request){
        UserinfoVO userinfoVO = new UserinfoVO();
        User user = UserSessionUtils.getSessionUser(request);
        if (user == null){
            return AjaxResult.fail(-1,"用户不存在");
        }
        userinfoVO.setPassword("");
        userinfoVO = userMapper.showUserinfo(user.getUserId());
        return AjaxResult.success(userinfoVO);
    }

    /**
     * 修改个人信息
     */
    @RequestMapping("/updateinfo")
    public AjaxResult updateinfo(HttpServletRequest request,String username,String gender,String showself,String place){
        UserinfoVO userinfoV0 = new UserinfoVO();
        User user = UserSessionUtils.getSessionUser(request);
        if (user == null || !StringUtils.hasLength(user.getUsername())){
            return AjaxResult.fail(-1,"用户不存在");
        }
        BeanUtils.copyProperties(user,userinfoV0);
        userinfoV0.setGender(gender);
        userinfoV0.setPlace(place);
        if (user.getWinCount() == 0 || user.getTotalCount() == 0){
            userinfoV0.setPercentage(String.valueOf(0));
        }else {
            double win  = (double) user.getWinCount();
            double total  = (double) user.getTotalCount();
            double n = win / total;
//            double n = (double) user.getWinCount() / user.getTotalCount();
            userinfoV0.setPercentage(String.valueOf(n));
        }
        userinfoV0.setUsername(username);
        userinfoV0.setShowself(showself);
        return AjaxResult.success(userMapper.updateUserinfo(userinfoV0));
    }

    /**
     * 设置密保
     */
    @RequestMapping("/secret")
    public AjaxResult addSecret(HttpServletRequest request, UserinfoSecret userinfoSecret){
        if (userinfoSecret == null || !StringUtils.hasLength(userinfoSecret.getQuestion())
                || !StringUtils.hasLength(userinfoSecret.getAnswer())) {
            return AjaxResult.fail(-2, "非法请求!");
        }
        User userinfo = UserSessionUtils.getSessionUser(request);
        if (userinfo == null) {
            return AjaxResult.fail(-2, "非法用户!");
        }
        userinfoSecret.setUserId(userinfo.getUserId());
        //密保加盐
        userinfoSecret.setAnswer(PasswordUtils.encrypt(userinfoSecret.getAnswer()));
        return AjaxResult.success(userMapper.addQuestion(userinfoSecret.getUserId(),userinfoSecret.getQuestion(),userinfoSecret.getAnswer()));
    }

    /**
     *  上传头像功能
     */
    @RequestMapping("/photo")
    public AjaxResult upLoadPhoto(@RequestPart("file") MultipartFile multipartFile,
                                  HttpServletRequest request) throws IOException {


        // 拿到登录用户
        User userinfo = UserSessionUtils.getSessionUser(request);
        if (userinfo == null) {
            return AjaxResult.fail(-1, "非法操作");
        }
        // 保存的根目录.
        StringBuilder filePath = new StringBuilder(AppVariable.UPLOADS_PATH); // D:\image
        //  StringBuilder filePath = new StringBuilder("D:\\image\\"); //
        // 根目录 + 唯一文件名
        String fileName = UUID.randomUUID().toString().replace("-", "");
        filePath.append(fileName);
        // 根目录 + 唯一文件名 + 后缀名
        String fileLastName = Objects.requireNonNull(multipartFile.getOriginalFilename()).substring(
                multipartFile.getOriginalFilename().lastIndexOf("."));
        filePath.append(fileLastName);
        System.out.println("文件路径: " + filePath.toString());
        multipartFile.transferTo(new File(filePath.toString()));
        // 保存好文件名后 在数据库中将 photo 字段文件名.
        String photo = "/photo/" + fileName + fileLastName;
        // 将评论表的头像进行修改
        int result = userMapper.upLodePhoto(photo, userinfo.getUserId());

        // 刷新 session
        HttpSession session = request.getSession();
        session.removeAttribute("user");
        session.setAttribute("user", userinfo);

        System.out.println(photo);
        return AjaxResult.success(result);
    }

    /**
     * 检查用户是否存在
     */
    @RequestMapping("/checkuser")
    private AjaxResult checkuser(String username){

        //1.得到当前登录用户(从 session 中获取)
        User userinfo = userMapper.selectByName(username);
        if (userinfo == null){
            return AjaxResult.fail(-1,"非法请求");
        }

        return AjaxResult.success(userinfo.getUserId());
    }


    /**
     * 修改密码
     */
    @RequestMapping("/updatesecret")
    public AjaxResult updatesecret(Integer uid,String password){
        if (password == null || uid == null){
            return AjaxResult.fail(-1,"非法参数");
        }
        User userinfo = userMapper.getUserById(uid);
        if (userinfo == null){
            return AjaxResult.fail(-2,"用户不存在!");
        }
        // 判断设置的密码和数据库中的密码是否相同
        if (PasswordUtils.check(password, userinfo.getPassword())) {
            // 修旧密码相同
            return AjaxResult.fail(-4, "修改密码与原密码相同!");
        }
        userMapper.updateUserSecret(PasswordUtils.encrypt(password),userinfo.getUserId());
        return AjaxResult.success(1);
    }

}
